﻿using Sai.Core.Introspection;
using Sai.Test.TestDataBuilders;
using TechTalk.SpecFlow;
using Xunit;
using Sai.Core;

namespace ApiDiff.Specs.Steps
{
	[Binding]
	public class MethodDeclarationSteps
	{
		const string oldVersionKey = "oldType";
		const string newVersionKey = "newType";
		const string methodNameKey = "methodName";
		const string returnTypeNameKey = "returnTypeName";

		[Given(@"I have a method named (.*) with return type (.*)")]
		public void GivenIHaveAMethodNamedWithReturnType(string methodName, string returnTypeName)
		{
			var collection = new MethodDeclarationCollection();

			collection.Add(MethodDeclarationBuilder.Method()
							.Named(methodName)
							.WithReturnType(new TypeName(returnTypeName))
							.Build());

			ScenarioContext.Current.Set(methodName, methodNameKey);
			ScenarioContext.Current.Set(returnTypeName, returnTypeNameKey);
			ScenarioContext.Current.Set<MethodDeclarationCollection>(collection, oldVersionKey);
		}

		[When(@"I remove the method in the new version")]
		public void WhenIRemoveTheMethodInTheNewVersion()
		{
			var collection = new MethodDeclarationCollection();
			ScenarioContext.Current.Set<MethodDeclarationCollection>(collection, newVersionKey);
		}

		[Then(@"there is an addition difference between the method versions")]
		public void ThenThereIsAnAdditionDifferenceBetweenTheMethodVersions()
		{
			var oldVersion = ScenarioContext.Current.Get<MethodDeclarationCollection>(oldVersionKey);
			var newVersion = ScenarioContext.Current.Get<MethodDeclarationCollection>(newVersionKey);

			ScenarioContext.Current.Pending();

			//var code = newVersion.DifferencesFrom(oldVersion);

			//Assert.True(code.HasAdditions);
			//Assert.Equal(1, code.Additions.Count);
		}

		[When(@"I add a method named (.*) with return type (.*) in the new version")]
		public void WhenIAddAMethodNamedWithReturnTypeInTheNewVersion(string methodName, string returnTypeName)
		{
			var oldVersion = ScenarioContext.Current.Get<MethodDeclarationCollection>(oldVersionKey);

			var collection = new MethodDeclarationCollection();

			collection.Add(MethodDeclarationBuilder.Method()
							.Named(oldVersion[0].Name)
							.WithReturnType(new TypeName(oldVersion[0].TypeName.FullName))
							.Build());

			collection.Add(MethodDeclarationBuilder.Method()
							.Named(methodName)
							.WithReturnType(new TypeName(returnTypeName))
							.Build());

			ScenarioContext.Current.Set<MethodDeclarationCollection>(collection, newVersionKey);
		}

		[Then(@"there is a removal difference between the method versions")]
		public void ThenThereIsARemovalDifferenceBetweenTheMethodVersions()
		{
			var oldVersion = ScenarioContext.Current.Get<MethodDeclarationCollection>(oldVersionKey);
			var newVersion = ScenarioContext.Current.Get<MethodDeclarationCollection>(newVersionKey);

			var removeChange = newVersion.FindRemovedMembers(oldVersion);

			Assert.Equal(1, removeChange.Count);
		}

		[Then(@"there is a change difference between the method versions")]
		public void ThenThereIsAChangeDifferenceBetweenTheMethodVersions()
		{
			var oldVersion = ScenarioContext.Current.Get<MethodDeclarationCollection>(oldVersionKey);
			var newVersion = ScenarioContext.Current.Get<MethodDeclarationCollection>(newVersionKey);

			ScenarioContext.Current.Pending();

			//var code = newVersion.DifferencesFrom(oldVersion);

			//Assert.True(code.HasAnyChanges);
		}

		[When(@"I mark the method obsolete in the new version")]
		public void WhenIMarkTheMethodObsoleteInTheNewVersion()
		{
			string methodName = ScenarioContext.Current.Get<string>(methodNameKey);
			string returnTypeName = ScenarioContext.Current.Get<string>(returnTypeNameKey);

			var collection = new MethodDeclarationCollection();

			collection.Add(MethodDeclarationBuilder.Method()
							.Named(methodName)
							.WithReturnType(new TypeName(returnTypeName))
							.IsObsolete()
							.Build());

			ScenarioContext.Current.Set<MethodDeclarationCollection>(collection, newVersionKey);
		}

		[Given(@"a method (.*) in (.*)")]
		public void GivenAMethodSignatureInVersion(string code, string version)
		{
			ScenarioContext.Current.Pending();
		}

		[Given(@"I remove the method in (.*)")]
		public void GivenIRemoveTheMethodInVersion()
		{
			ScenarioContext.Current.Pending();
		}

		[Then(@"the method should be removed")]
		public void ThenTheMethodShouldBeRemoved()
		{
			ScenarioContext.Current.Pending();
		}

		[When(@"I compare ""v1"" and ""v2""")]
		public void WhenICompareVersionAndVersion()
		{
			ScenarioContext.Current.Pending();
		}
	}
}
